package com.jf.anmocker.plugin.injector

import com.jf.mocker.anotations.IClassMocker
import javassist.ClassPool
import org.objectweb.asm.ClassReader
import java.io.File

/**
 * @Class: ClassCollector
 * @Description:
 * @author:
 * @Date: 2022/9/27
 */
class AMClassCollector(var mClassPool : ClassPool) {

    //缓存读取的所有相关class
    private val classMap = HashMap<String, InjectEntity>()
    //緩存annotation，标记需要mock的类
    private val annotationMap = HashMap<String, MutableList<AnoEntity>>()

    fun getClassMap() : HashMap<String, InjectEntity>{
        return classMap
    }

    fun getAnnotationMap() : HashMap<String, MutableList<AnoEntity>>{
        return annotationMap
    }

    fun collectClassFileFromDir(directoryFile: File?) {
        if (directoryFile == null) {
            return
        }
        if(!directoryFile.isDirectory){
            if (directoryFile.absolutePath.endsWith(FileFilterConst.CLASS_SUFFIX)) {
                mClassPool.appendClassPath(directoryFile.absolutePath)
                collectClassFile(directoryFile.absolutePath, directoryFile)
            }else{
                println("ClassCollector >>> collectClassFile jump >>> ${directoryFile.absolutePath}")
            }
        }else{
            collectClassFileFromDir(directoryFile.absolutePath)
        }
    }

    fun collectClassFileFromDir(absolutePath: String) {
        //添加路径
        mClassPool.appendClassPath(absolutePath)
        //遍历所有类文件
        val list = FileFilter.getClassFileList(absolutePath)
        println("ClassCollector >>> collectClassFileFromDir >>> ${list?.size ?: 0} from $absolutePath")
        if (list != null && list.size > 0) {
            list.forEach{ collectClassFile(absolutePath, it) }
        }
    }

    fun collectClassFileFromJar(jarFile: File?){
        if (jarFile == null) {
            return
        }
    }

    private fun collectClassFile(classRootPath : String, file : File){
        val inputStream = file.inputStream()
        try{
            val reader = ClassReader(inputStream)
            val className = reader.className.replace('/', '.')
            if(!FileFilter.filterClassName(className)){
                println("ClassCollector >>> collectClassFile jump >>> $className")
                return
            }else{
                println("ClassCollector >>> read class to pool >>> $className")
            }
            val tempCls = mClassPool.getOrNull(className)
            if(tempCls == null){
                println("ClassCollector >>> collectClassFile not found >>> $className")
                return
            }
            val classMocker = tempCls.getAnnotation(IClassMocker::class.java)
            if(classMocker is IClassMocker){
                if(annotationMap[classMocker.value] == null){
                    annotationMap[classMocker.value] = mutableListOf(AnoEntity(classMocker, tempCls))
                }else{
                    annotationMap[classMocker.value]!!.add(AnoEntity(classMocker, tempCls))
                }
                println("ClassCollector >>> collectClassFile[annotation] >>> $className")
            }else{
                classMap[tempCls.name] = InjectEntity(classRootPath, tempCls)
                println("ClassCollector >>> collectClassFile[class] >>> $className")
            }
        }catch (e: Exception){
            e.printStackTrace()
        }finally {
            inputStream.close()
        }
    }

}